/*!
 * \file WtExecRunner.cpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 执行监控运行器实现
 * 
 * \details 本文件实现了WonderTrader执行监控系统的核心运行器类WtExecRunner，
 *          负责整个执行监控系统的初始化、配置、运行和管理。
 *          
 *          主要实现功能：
 *          - 系统组件的生命周期管理
 *          - 行情解析器和交易通道的初始化和管理
 *          - 执行器工厂和执行管理器的协调
 *          - 基础数据和热点合约管理
 *          - 实时行情处理和分发
 *          - 持仓目标设置和执行监控
 *          - 跨平台支持和异常处理
 *          
 *          该实现是执行监控系统的核心控制器，协调各个组件的工作。
 */
#include "WtExecRunner.h"

#include "../WtCore/WtHelper.h"
#include "../WTSTools/WTSLogger.h"
#include "../WTSUtils/WTSCfgLoader.h"

#include "../Includes/WTSContractInfo.hpp"
#include "../Includes/WTSVariant.hpp"
#include "../Share/CodeHelper.hpp"
#include "../Share/ModuleHelper.hpp"
#include "../Share/TimeUtils.hpp"
#include "../WTSUtils/SignalHook.hpp"

#ifdef _MSC_VER
#include "../Common/mdump.h"
#include <boost/filesystem.hpp>

/*!
 * \brief 获取模块名称（Windows专用）
 * 
 * \details 获取当前模块的文件名，用于内存转储文件命名。
 *          该函数仅在Windows平台下使用。
 * 
 * \return 模块文件名字符串指针
 * 
 * \note 返回的字符串指向静态内存，无需释放
 */
const char* getModuleName()
{
	static char MODULE_NAME[250] = { 0 };
	if (strlen(MODULE_NAME) == 0)
	{

		GetModuleFileName(g_dllModule, MODULE_NAME, 250);
		boost::filesystem::path p(MODULE_NAME);
		strcpy(MODULE_NAME, p.filename().string().c_str());
	}

	return MODULE_NAME;
}
#endif

/*!
 * \brief 构造函数
 * 
 * \details 初始化执行监控运行器，设置信号处理钩子。
 *          在Windows系统中禁用信号钩子，在Unix系统中启用信号钩子
 *          用于捕获系统信号并记录到日志中。
 */
WtExecRunner::WtExecRunner()
{
#if _WIN32
// Signal hooks disabled in WIN32
#else
// Signal hooks enabled in UNIX
	install_signal_hooks([](const char* message) {
		WTSLogger::error(message);
	});
#endif
}

/*!
 * \brief 初始化执行监控系统
 * 
 * \details 初始化日志系统、设置安装目录、启用内存转储（Windows）。
 *          该函数必须在其他操作之前调用。
 * 
 * \param logCfg 日志配置文件路径，默认为"logcfgexec.json"
 * \param isFile 是否为文件路径，true表示文件路径，false表示配置内容
 * \return 初始化是否成功
 * 
 * \note Windows系统下会启用内存转储功能用于调试
 */
bool WtExecRunner::init(const char* logCfg /* = "logcfgexec.json" */, bool isFile /* = true */)
{
#ifdef _MSC_VER
	CMiniDumper::Enable(getModuleName(), true, WtHelper::getCWD().c_str());
#endif

	if(isFile)
	{
		std::string path = WtHelper::getCWD() + logCfg;
		WTSLogger::init(path.c_str(), true);
	}
	else
	{
		WTSLogger::init(logCfg, false);
	}
	

	WtHelper::setInstDir(getBinDir());
	return true;
}

/*!
 * \brief 配置执行监控系统
 * 
 * \details 加载系统配置文件，初始化各个组件包括：
 *          - 基础数据管理器（交易时段、品种、合约、节假日）
 *          - 数据管理器
 *          - 行为策略管理器
 *          - 行情解析器
 *          - 交易适配器
 *          - 执行器
 * 
 * \param cfgFile 配置文件路径或配置内容
 * \param isFile 是否为文件路径，true表示文件路径，false表示配置内容
 * \return 配置是否成功
 * 
 * \note 配置文件应包含parsers、traders、executers等节点
 */
bool WtExecRunner::config(const char* cfgFile, bool isFile /* = true */)
{
	_config = isFile ? WTSCfgLoader::load_from_file(cfgFile, true) : WTSCfgLoader::load_from_content(cfgFile, false, true);
	if(_config == NULL)
	{
		WTSLogger::log_raw(LL_ERROR, "Loading config file failed");
		return false;
	}

	//加载基础数据文件
	WTSVariant* cfgBF = _config->get("basefiles");
	bool isUTF8 = cfgBF->getBoolean("utf-8");
	if (cfgBF->get("session"))
	{
		_bd_mgr.loadSessions(cfgBF->getCString("session"), isUTF8);
		WTSLogger::info("Trading sessions loaded");
	}

	WTSVariant* cfgItem = cfgBF->get("commodity");
	if (cfgItem)
	{
		if (cfgItem->type() == WTSVariant::VT_String)
		{
			_bd_mgr.loadCommodities(cfgItem->asCString(), isUTF8);
		}
		else if (cfgItem->type() == WTSVariant::VT_Array)
		{
			for (uint32_t i = 0; i < cfgItem->size(); i++)
			{
				_bd_mgr.loadCommodities(cfgItem->get(i)->asCString(), isUTF8);
			}
		}
	}

	cfgItem = cfgBF->get("contract");
	if (cfgItem)
	{
		if (cfgItem->type() == WTSVariant::VT_String)
		{
			_bd_mgr.loadContracts(cfgItem->asCString(), isUTF8);
		}
		else if (cfgItem->type() == WTSVariant::VT_Array)
		{
			for (uint32_t i = 0; i < cfgItem->size(); i++)
			{
				_bd_mgr.loadContracts(cfgItem->get(i)->asCString(), isUTF8);
			}
		}
	}

	if (cfgBF->get("holiday"))
	{
		_bd_mgr.loadHolidays(cfgBF->getCString("holiday"));
		WTSLogger::info("Holidays loaded");
	}


	//初始化数据管理
	initDataMgr();

	//初始化行为策略
	if (!initActionPolicy())
		return false;

	//初始化行情通道
	const char* cfgParser = _config->getCString("parsers");
	if (StdFile::exists(cfgParser))
	{
		WTSLogger::info_f("Reading parser config from {}...", cfgParser);
		WTSVariant* var = WTSCfgLoader::load_from_file(cfgParser, true);
		if (var)
		{
			if (!initParsers(var))
				WTSLogger::error("Loading parsers failed");
			var->release();
		}
		else
		{
			WTSLogger::error_f("Loading parser config {} failed", cfgParser);
		}
	}

	//初始化交易通道
	const char* cfgTraders = _config->getCString("traders");
	if (StdFile::exists(cfgTraders))
	{
		WTSLogger::info_f("Reading trader config from {}...", cfgTraders);
		WTSVariant* var = WTSCfgLoader::load_from_file(cfgTraders, true);
		if (var)
		{
			if (!initTraders(var))
				WTSLogger::error("Loading traders failed");
			var->release();
		}
		else
		{
			WTSLogger::error_f("Loading trader config {} failed", cfgTraders);
		}
	}

	const char* cfgExecuters = _config->getCString("executers");
	if (StdFile::exists(cfgExecuters))
	{
		WTSLogger::info_f("Reading executer config from {}...", cfgExecuters);
		WTSVariant* var = WTSCfgLoader::load_from_file(cfgExecuters, true);
		if (var)
		{
			if (!initExecuters(var))
				WTSLogger::error("Loading executers failed");
			var->release();
		}
		else
		{
			WTSLogger::error_f("Loading executer config {} failed", cfgExecuters);
		}
	}

	return true;
}

/*!
 * \brief 运行执行监控系统
 * 
 * \details 启动行情解析器和交易适配器，开始接收行情数据和处理交易。
 *          该函数会启动所有已配置的组件，系统进入运行状态。
 *          包含异常处理机制，确保系统稳定运行。
 * 
 * \note 该函数可能会阻塞，直到系统停止运行
 */
void WtExecRunner::run()
{
	try
	{
		_parsers.run();
		_traders.run();
	}
	catch (...)
	{
		print_stack_trace([](const char* message) {
			WTSLogger::error(message);
		});
	}
}

/*!
 * \brief 初始化行情解析器
 * 
 * \details 根据配置信息初始化行情解析器，建立行情数据接收通道。
 *          支持多个行情解析器的配置和管理，每个解析器可以连接不同的行情源。
 * 
 * \param cfgParser 行情解析器配置信息
 * \return 初始化是否成功
 * 
 * \note 如果解析器ID为空，系统会自动生成唯一ID
 */
bool WtExecRunner::initParsers(WTSVariant* cfgParser)
{
	WTSVariant* cfg = cfgParser->get("parsers");
	if (cfg == NULL)
		return false;

	uint32_t count = 0;
	for (uint32_t idx = 0; idx < cfg->size(); idx++)
	{
		WTSVariant* cfgItem = cfg->get(idx);
		if (!cfgItem->getBoolean("active"))
			continue;

		const char* id = cfgItem->getCString("id");

		// By Wesley @ 2021.12.14
		// 如果id为空，自动生成id
		std::string realid = id;
		if (realid.empty())
		{
			static uint32_t auto_parserid = 1000;
			realid = StrUtil::printf("auto_parser_%u", auto_parserid++);
		}

		ParserAdapterPtr adapter(new ParserAdapter);
		adapter->init(realid.c_str(), cfgItem, this, &_bd_mgr, &_hot_mgr);
		_parsers.addAdapter(realid.c_str(), adapter);

		count++;
	}

	WTSLogger::info("%u parsers loaded", count);

	return true;
}

/*!
 * \brief 初始化执行器
 * 
 * \details 根据配置信息初始化执行器，设置执行算法和参数。
 *          首先加载执行器工厂，然后为每个配置的执行器创建实例，
 *          并关联对应的交易适配器。
 * 
 * \param cfgExecuter 执行器配置信息
 * \return 初始化是否成功
 * 
 * \note 每个执行器必须配置对应的交易适配器才能正常工作
 */
bool WtExecRunner::initExecuters(WTSVariant* cfgExecuter)
{
	WTSVariant* cfg = cfgExecuter->get("executers");
	if (cfg == NULL || cfg->type() != WTSVariant::VT_Array)
		return false;

	//加载执行器工厂
	std::string path = WtHelper::getInstDir() + "executer//";
	_exe_factory.loadFactories(path.c_str());

	uint32_t count = 0;
	for (uint32_t idx = 0; idx < cfg->size(); idx++)
	{
		WTSVariant* cfgItem = cfg->get(idx);
		if (!cfgItem->getBoolean("active"))
			continue;

		const char* id = cfgItem->getCString("id");

		WtExecuterPtr executer(new WtLocalExecuter(&_exe_factory, id, &_data_mgr));
		executer->setStub(this);
		if (!executer->init(cfgItem))
			return false;

		const char* tid = cfgItem->getCString("trader");
		if (strlen(tid) == 0)
		{
			WTSLogger::error("No Trader configured for Executer %s", id);
		}
		else
		{
			TraderAdapterPtr trader = _traders.getAdapter(tid);
			if (trader)
			{
				executer->setTrader(trader.get());
				trader->addSink(executer.get());
			}
			else
			{
				WTSLogger::error("Trader %s not exists, cannot configured for executer %s", tid, id);
			}
		}

		_exe_mgr.add_executer(executer);

		count++;
	}

	WTSLogger::info("%u executers loaded", count);

	return true;
}

/*!
 * \brief 初始化交易适配器
 * 
 * \details 根据配置信息初始化交易适配器，建立与交易系统的连接。
 *          支持多个交易适配器的配置和管理，每个适配器可以连接不同的交易系统。
 * 
 * \param cfgTrader 交易适配器配置信息
 * \return 初始化是否成功
 * 
 * \note 交易适配器需要配置基础数据管理器和行为策略管理器
 */
bool WtExecRunner::initTraders(WTSVariant* cfgTrader)
{
	WTSVariant* cfg = cfgTrader->get("traders");
	if (cfg == NULL || cfg->type() != WTSVariant::VT_Array)
		return false;

	uint32_t count = 0;
	for (uint32_t idx = 0; idx < cfg->size(); idx++)
	{
		WTSVariant* cfgItem = cfg->get(idx);
		if (!cfgItem->getBoolean("active"))
			continue;

		const char* id = cfgItem->getCString("id");

		TraderAdapterPtr adapter(new TraderAdapter);
		adapter->init(id, cfgItem, &_bd_mgr, &_act_policy);

		_traders.addAdapter(id, adapter);
		count++;
	}

	WTSLogger::info("%u traders loaded", count);

	return true;
}

/*!
 * \brief 初始化数据管理器
 * 
 * \details 初始化简单数据管理器，设置数据存储和缓存机制。
 *          数据管理器负责管理实时行情数据和历史数据的访问。
 * 
 * \return 初始化是否成功
 * 
 * \note 数据管理器的配置信息从主配置文件的"data"节点获取
 */
bool WtExecRunner::initDataMgr()
{
	WTSVariant* cfg = _config->get("data");
	if (cfg == NULL)
		return false;

	_data_mgr.init(cfg, this);

	WTSLogger::info("Data Manager initialized");
	return true;
}

/*!
 * \brief 添加执行器工厂
 * 
 * \details 从指定文件夹加载执行器工厂动态库，扩展系统的执行器类型。
 *          支持加载多种执行算法，如TWAP、VWAP、最小冲击等。
 * 
 * \param folder 执行器工厂动态库所在文件夹路径
 * \return 加载是否成功
 * 
 * \note 执行器工厂必须实现标准的工厂接口
 */
bool WtExecRunner::addExeFactories(const char* folder)
{
	return _exe_factory.loadFactories(folder);
}

/*!
 * \brief 获取交易时段信息
 * 
 * \details 根据时段ID或合约代码获取对应的交易时段信息。
 *          支持两种查询方式：直接通过时段ID查询，或通过合约代码查询。
 * 
 * \param sid 时段ID或合约代码
 * \param isCode 是否为合约代码，true表示合约代码，false表示时段ID
 * \return 交易时段信息指针，未找到时返回NULL
 * 
 * \note 通过合约代码查询时，会先获取品种信息，再获取对应的交易时段
 */
WTSSessionInfo* WtExecRunner::get_session_info(const char* sid, bool isCode /* = true */)
{
	if (!isCode)
		return _bd_mgr.getSession(sid);

	WTSCommodityInfo* cInfo = _bd_mgr.getCommodity(CodeHelper::stdCodeToStdCommID(sid).c_str());
	if (cInfo == NULL)
		return NULL;

	return _bd_mgr.getSession(cInfo->getSession());
}

/*!
 * \brief 处理实时行情数据推送
 * 
 * \details 接收行情解析器推送的实时tick数据，进行以下处理：
 *          1. 获取或设置合约信息
 *          2. 更新系统时间和交易日
 *          3. 转换合约代码为标准格式
 *          4. 更新数据管理器缓存
 *          5. 通知执行管理器处理
 * 
 * \param quote 当前tick数据指针
 * \param hotFlag 热点标志，用于标识主力合约等信息
 * 
 * \note 该函数是行情数据处理的入口点，支持期货期权、月合约、平合约等多种类型
 */
void WtExecRunner::handle_push_quote(WTSTickData* quote, uint32_t hotFlag /* = 0 */)
{
	WTSContractInfo* cInfo = quote->getContractInfo();
	if (cInfo == NULL)
	{
		cInfo = _bd_mgr.getContract(quote->code(), quote->exchg());
		quote->setContractInfo(cInfo);
	}

	if (cInfo == NULL)
		return;

	uint32_t uDate = quote->actiondate();
	uint32_t uTime = quote->actiontime();
	uint32_t curMin = uTime / 100000;
	uint32_t curSec = uTime % 100000;
	WtHelper::setTime(uDate, curMin, curSec);
	WtHelper::setTDate(quote->tradingdate());

	WTSCommodityInfo* commInfo = cInfo->getCommInfo();

	std::string stdCode;
	if (commInfo->getCategoty() == CC_FutOption)
	{
		stdCode = CodeHelper::rawFutOptCodeToStdCode(cInfo->getCode(), cInfo->getExchg());
	}
	else if (CodeHelper::isMonthlyCode(quote->code()))
	{
		stdCode = CodeHelper::rawMonthCodeToStdCode(cInfo->getCode(), cInfo->getExchg());
	}
	else
	{
		stdCode = CodeHelper::rawFlatCodeToStdCode(cInfo->getCode(), cInfo->getExchg(), cInfo->getProduct());
	}
	quote->setCode(stdCode.c_str());
	_data_mgr.handle_push_quote(stdCode.c_str(), quote);

	_exe_mgr.handle_tick(stdCode.c_str(), quote);
}

/*!
 * \brief 释放系统资源
 * 
 * \details 停止所有组件的运行，释放分配的资源。
 *          该函数应在系统退出前调用，主要停止日志系统。
 * 
 * \note 调用该函数后，系统将停止所有监控和执行活动
 */
void WtExecRunner::release()
{
	WTSLogger::stop();
}

/*!
 * \brief 设置持仓目标
 * 
 * \details 为指定合约设置目标持仓量，执行管理器将根据当前持仓
 *          和目标持仓的差异，通过配置的执行器执行相应的交易指令。
 * 
 * \param stdCode 标准合约代码（如：SHFE.rb2101）
 * \param targetPos 目标持仓量，正数为多头，负数为空头，0为平仓
 * 
 * \note 执行器将根据配置的执行策略（如TWAP、最小冲击等）执行交易
 */
void WtExecRunner::setPosition(const char* stdCode, double targetPos)
{
	_exe_mgr.handle_pos_change(stdCode, targetPos);
}

/*!
 * \brief 初始化行为策略
 * 
 * \details 初始化行为策略管理器，设置交易行为控制策略。
 *          行为策略用于控制交易行为，如买卖限制、风险控制等。
 * 
 * \return 初始化是否成功
 * 
 * \note 行为策略配置文件路径从主配置文件的"bspolicy"节点获取
 */
bool WtExecRunner::initActionPolicy()
{
	const char* action_file = _config->getCString("bspolicy");
	if (strlen(action_file) <= 0)
		return false;

	bool ret = _act_policy.init(action_file);
	WTSLogger::info("Action policies initialized");
	return ret;
}

/*!
 * \brief 获取实时时间
 * 
 * \details 获取当前的实时时间戳，用于执行器的时间相关计算。
 *          时间戳由日期、原始时间和秒数组合而成。
 * 
 * \return 实时时间戳（微秒级）
 * 
 * \note 时间信息来源于数据管理器维护的当前时间
 */
uint64_t WtExecRunner::get_real_time()
{
	return TimeUtils::makeTime(_data_mgr.get_date(), _data_mgr.get_raw_time() * 100000 + _data_mgr.get_secs());
}

/*!
 * \brief 获取品种信息
 * 
 * \details 根据标准合约代码获取对应的品种信息。
 *          品种信息包含交易规则、手续费、保证金等重要参数。
 * 
 * \param stdCode 标准合约代码
 * \return 品种信息指针，未找到时返回NULL
 * 
 * \note 会先将标准合约代码转换为品种ID，再查询品种信息
 */
WTSCommodityInfo* WtExecRunner::get_comm_info(const char* stdCode)
{
	return _bd_mgr.getCommodity(CodeHelper::stdCodeToStdCommID(stdCode).c_str());
}

/*!
 * \brief 获取交易时段信息
 * 
 * \details 根据标准合约代码获取对应的交易时段信息。
 *          交易时段信息包含开盘时间、收盘时间、休市时间等。
 * 
 * \param stdCode 标准合约代码
 * \return 交易时段信息指针，未找到时返回NULL
 * 
 * \note 会先获取品种信息，再通过品种的交易时段ID获取时段信息
 */
WTSSessionInfo* WtExecRunner::get_sess_info(const char* stdCode)
{
	WTSCommodityInfo* cInfo = _bd_mgr.getCommodity(CodeHelper::stdCodeToStdCommID(stdCode).c_str());
	if (cInfo == NULL)
		return NULL;

	return _bd_mgr.getSession(cInfo->getSession());
}

/*!
 * \brief 获取交易日
 * 
 * \details 获取当前的交易日期，用于执行器的日期相关计算。
 * 
 * \return 交易日期（格式：yyyyMMdd）
 * 
 * \note 交易日信息来源于数据管理器维护的当前交易日
 */
uint32_t WtExecRunner::get_trading_day()
{
	return _data_mgr.get_trading_day();
}